home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 15 / BBS in a box XV-1.iso / Files / Game / B / BoloRandomMap 1.10.sit / Bolo RandomMap 1.1.0 / Bolo RandomMap.p < prev    next >
Encoding:
Text File  |  1993-07-01  |  18.4 KB  |  879 lines  |  [TEXT/PJMM]

  1. program BoloRandomMap;
  2.  
  3. { Bolo RandomMap © Peter N Lewis, 1993 }
  4. { This source code is free and may be used for any purpose }
  5.  
  6.     uses
  7.         MyUtils, MyDialogs, FixMath, MyUtilities, MyStandardFile;
  8.  
  9. {$D-}
  10.     const
  11.         max_rows = 255;
  12.         max_cols = 255;
  13.         max_height = 255;
  14.         max_pillboxes = 16;
  15.         max_bases = 16;
  16.         max_starts = 16;
  17.         max_que = 256;
  18.  
  19.     type
  20.         lands = (L_Building, L_River, L_Swamp, L_Crater, L_Road, L_Forest, L_Rubble, L_Grass,{}
  21.             L_ShotBuilding, L_Boat, L_MSwamp, L_MCrater, L_MRoad, L_MForest, L_MRubble, L_MGrass,{}
  22.             L_DeepSea);
  23.         landSet = set of lands;
  24.  
  25.     const
  26.         L_First = L_Building;
  27.         L_Last = L_DeepSea;
  28.         All_Locations = [L_First..L_Last];
  29.         flat_set = [L_Swamp, L_Crater, L_Road, L_Forest, L_Rubble, L_Grass];
  30.  
  31.     type
  32.         mapArray = packed array[1..max_rows, 1..max_cols] of byte;
  33.         mapPtr = ^mapArray;
  34.         landArray = packed array[1..max_rows, 1..max_cols] of lands;
  35.         landPtr = ^landArray;
  36.         location = record
  37.                 r, c: integer;
  38.             end;
  39.  
  40.     const
  41.         version = 1;
  42.         land_strs = '# %C*^RX=BABCDEF~';
  43.  
  44.     var
  45.         rows, cols, land, forest: integer;
  46.         mp, mp2: mapPtr;
  47.         lp, lp2: landPtr;
  48.         pillboxes, bases: integer;
  49.         base_armour, base_shells, base_mines: integer;
  50.         pillbox_locations: array[1..max_pillboxes] of location;
  51.         base_locations: array[1..max_bases] of location;
  52.         que: array[0..max_que] of location;
  53.         q_head, q_tail, q_size: integer;
  54.         display: dialogPtr;
  55.         prog_parts, prog_parts_done, prog_base, prog_base_done: integer;
  56.         random_location_failed: boolean;
  57.  
  58.     procedure DrawProgress (dlg: dialogPtr; item: integer);
  59.         const
  60.             HiliteRGBP = $DA0;
  61.         type
  62.             RGBColorPtr = ^RGBColor;
  63.         var
  64.             box: rect;
  65.             w, uw: integer;
  66.             oldfore: RGBColor;
  67.     begin
  68.         Setport(dlg);
  69.         GetDItemRect(dlg, item, box);
  70.         FrameRect(box);
  71.         InsetRect(box, 1, 1);
  72.         with box do begin
  73.             w := right - left;
  74.             uw := FracMul(w, FracDiv(prog_base * prog_parts_done + prog_base_done, prog_parts * prog_base));
  75.             right := left + uw;
  76.             if has_colorQD and false then begin
  77.                 GetForeColor(oldfore);
  78.                 RGBForeColor(RGBColorPtr(HiliteRGBP)^);
  79.                 PaintRect(box);
  80.                 RGBForeColor(oldfore);
  81.             end
  82.             else
  83.                 FillRect(box, gray);
  84.             left := right;
  85.             right := right + w - uw;
  86.             EraseRect(box);
  87.         end;
  88.     end;
  89.  
  90.     procedure WNE;
  91.         var
  92.             dummy: boolean;
  93.             er: eventRecord;
  94.             dlg: dialogPtr;
  95.             item: integer;
  96.     begin
  97.         DrawProgress(display, 1);
  98.         dummy := WaitNextEvent(everyEvent, er, 1, nil);
  99.         if IsDialogEvent(er) then
  100.             dummy := DialogSelect(er, dlg, item);
  101.     end;
  102.  
  103.     procedure StartPart (base: longInt);
  104.         var
  105.             s: str255;
  106.     begin
  107.         prog_parts_done := prog_parts_done + 1;
  108.         GetIndString(s, 201, prog_parts_done + 1);
  109.         SetItemText(display, 11, s);
  110.         prog_base_done := 0;
  111.         prog_base := base;
  112.     end;
  113.  
  114.     procedure ProgRow (r: integer);
  115.     begin
  116.         if r > prog_base then
  117.             r := prog_base;
  118.         prog_base_done := r;
  119.         WNE;
  120.     end;
  121.  
  122.     procedure InitQue;
  123.     begin
  124.         q_head := 0;
  125.         q_tail := 0;
  126.         q_size := 0;
  127.     end;
  128.  
  129.     procedure AddQue (var l: location);
  130.     begin
  131.         if q_size < max_que then begin
  132.             que[q_head] := l;
  133.             q_head := (q_head + 1) mod max_que;
  134.             q_size := q_size + 1;
  135.         end;
  136.     end;
  137.  
  138.     procedure GetQue (var l: location);
  139.     begin
  140.         if q_size > 0 then begin
  141.             l := que[q_tail];
  142.             q_tail := (q_tail + 1) mod max_que;
  143.             q_size := q_size - 1;
  144.         end;
  145.     end;
  146.  
  147.     function EmptyQue: boolean;
  148.     begin
  149.         EmptyQue := q_size = 0;
  150.     end;
  151.  
  152.     function Rand (n: longInt): longInt;
  153.     begin
  154.         Rand := BAND(BOR(BSL(longInt(Random), 16), BAND(Random, $7FFF)), $7FFFFFFF) mod n;
  155.     end;
  156.  
  157.     function RandBetween (a, b: longInt): longInt;
  158.     begin
  159.         if b = a then begin
  160.             RandBetween := a;
  161.         end
  162.         else begin
  163.             RandBetween := a + Rand(b - a + 1);
  164.         end;
  165.     end;
  166.  
  167.     procedure DrawMap;
  168.         var
  169.             r, c: integer;
  170.             s: str255;
  171.     begin
  172.         for r := 1 to rows do begin
  173.  {$PUSH}
  174. {$R-}
  175.             s[0] := chr(cols * 2);
  176. {$POP}
  177.             for c := 1 to cols do begin
  178.                 s[c * 2 - 1] := land_strs[mp^[r, c] + 1];
  179.                 s[c * 2] := land_strs[mp^[r, c] + 1];
  180.             end;
  181.             writeln(s);
  182.         end;
  183.     end;
  184.  
  185.     function CalcPercentage (h: integer): integer;
  186.         var
  187.             r, c: integer;
  188.             count: longInt;
  189.     begin
  190.         count := 0;
  191.         for r := 1 to rows do begin
  192.             for c := 1 to cols do begin
  193.                 if mp^[r, c] >= h then
  194.                     count := count + 1;
  195.             end;
  196.         end;
  197.         CalcPercentage := count * 100 div (longInt(rows - 2) * (cols - 2)); { allow for edge sea squares }
  198.     end;
  199.  
  200.     function FindHeight (p: integer): integer;
  201.         var
  202.             h: integer;
  203.             min, max, pp: integer;
  204.     begin
  205.         min := 0;
  206.         max := max_height;
  207.         while (min < max) do begin
  208.             h := (min + max) div 2;
  209.             pp := CalcPercentage(h);
  210.             if p = pp then begin
  211.                 leave;
  212.             end
  213.             else if pp < p then begin
  214.                 max := h - 1;
  215.             end
  216.             else begin
  217.                 min := h + 1;
  218.             end;
  219.         end;
  220.         FindHeight := min;
  221.     end;
  222.  
  223.     procedure Threshold (h: integer);
  224.         var
  225.             r, c: integer;
  226.     begin
  227.         StartPart(rows);
  228.         for r := 1 to rows do begin
  229.             ProgRow(r);
  230.             for c := 1 to cols do begin
  231.                 mp^[r, c] := ord(mp^[r, c] >= h);
  232.             end;
  233.         end;
  234.     end;
  235.  
  236.     procedure RandomHeights;
  237.         function GetFactor (i, max: integer): integer;
  238.             var
  239.                 f: integer;
  240.         begin
  241.             f := max - i + 1;
  242.             if f > i then
  243.                 f := i;{ f=distance from edge, starting at 1 }
  244.             if f > 4 then
  245.                 f := 4;
  246.             f := 5 - f;
  247.             GetFactor := f;
  248.         end;
  249.  
  250.         var
  251.             r, c: integer;
  252.             dr, dc: integer;
  253.     begin
  254.         StartPart(rows);
  255.         for r := 1 to rows do begin
  256.             ProgRow(r);
  257.             dr := GetFactor(r, rows);
  258.             for c := 1 to cols do begin
  259.                 dc := GetFactor(c, cols);
  260.                 mp^[r, c] := Rand(max_height div dr div dc);
  261.             end;
  262.         end;
  263.     end;
  264.  
  265.     procedure Smooth;
  266.         var
  267.             r, c, dr, dc, rr, cc, v, count: integer;
  268.     begin
  269.         StartPart(rows);
  270.         mp2^ := mp^;
  271.         for r := 1 to rows do begin
  272.             ProgRow(r);
  273.             for c := 1 to cols do begin
  274.                 v := 0;
  275.                 for dr := -2 to 2 do begin
  276.                     for dc := -2 to 2 do begin
  277.                         rr := r + dr;
  278.                         cc := c + dc;
  279.                         if (1 <= rr) & (rr <= rows) & (1 <= cc) & (cc <= cols) then begin
  280.                             v := v + mp2^[rr, cc];
  281.                         end;
  282.                     end;
  283.                 end;
  284.                 mp^[r, c] := v div 25;
  285.             end;
  286.         end;
  287.     end;
  288.  
  289.     procedure LoseIslands;
  290.         var
  291.             r, c, dr, dc, rr, cc, count: integer;
  292.     begin
  293.         StartPart(rows);
  294.         mp2^ := mp^;
  295.         for r := 1 to rows do begin
  296.             ProgRow(r);
  297.             for c := 1 to cols do begin
  298.                 count := 0;
  299.                 for dr := -1 to 1 do begin
  300.                     for dc := -1 to 1 do begin
  301.                         if (dr <> 0) | (dc <> 0) then begin
  302.                             rr := r + dr;
  303.                             cc := c + dc;
  304.                             if (1 <= rr) & (rr <= rows) & (1 <= cc) & (cc <= cols) then begin
  305.                                 count := count + mp2^[rr, cc];
  306.                             end;
  307.                         end;
  308.                     end;
  309.                 end;
  310.                 if count = 0 then
  311.                     mp^[r, c] := 0
  312.                 else if count = 8 then
  313.                     mp^[r, c] := 1;
  314.             end;
  315.         end;
  316.     end;
  317.  
  318.     procedure TrimEdges;
  319.         var
  320.             r, c: integer;
  321.     begin
  322.         for r := 1 to rows do begin
  323.             mp^[r, 1] := 0;
  324.             mp^[r, cols] := 0;
  325.         end;
  326.         for c := 1 to cols do begin
  327.             mp^[1, c] := 0;
  328.             mp^[rows, c] := 0;
  329.         end;
  330.     end;
  331.  
  332.     procedure ConvertToLand;
  333.         var
  334.             r, c, dr, dc, rr, cc, count: integer;
  335.     begin
  336.         StartPart(rows);
  337.         for r := 1 to rows do begin
  338.             ProgRow(r);
  339.             for c := 1 to cols do begin
  340.                 if mp^[r, c] = 0 then begin
  341.                     lp^[r, c] := L_River;
  342.                 end
  343.                 else begin
  344.                     lp^[r, c] := L_Grass;
  345.                 end;
  346.             end;
  347.         end;
  348.     end;
  349.  
  350.     procedure InitLocations;
  351.         var
  352.             i: integer;
  353.     begin
  354.         random_location_failed := false;
  355.         for i := 1 to max_pillboxes do begin
  356.             pillbox_locations[i].r := -1;
  357.             pillbox_locations[i].c := -1;
  358.         end;
  359.         for i := 1 to max_bases do begin
  360.             base_locations[i].r := -1;
  361.             base_locations[i].c := -1;
  362.         end;
  363.     end;
  364.  
  365.     procedure GetRandomLandLocation (var l: location; ls: landSet);
  366.         var
  367.             good: boolean;
  368.             i: integer;
  369.             loopcheck: integer;
  370.     begin
  371.         loopcheck := 200;
  372.         repeat
  373.             l.r := RandBetween(1, rows);
  374.             l.c := RandBetween(1, cols);
  375.             good := lp^[l.r, l.c] in ls;
  376.             if good then begin
  377.                 for i := 1 to max_pillboxes do begin
  378.                     if (pillbox_locations[i].r = l.r) and (pillbox_locations[i].c = l.c) then
  379.                         good := false;
  380.                 end;
  381.                 for i := 1 to max_bases do begin
  382.                     if (base_locations[i].r = l.r) and (base_locations[i].c = l.c) then
  383.                         good := false;
  384.                 end;
  385.             end;
  386.             loopcheck := loopcheck - 1;
  387.         until good or (loopcheck = 0);
  388.         if not good then begin
  389.             random_location_failed := true;
  390.         end;
  391.     end;
  392.  
  393.     procedure GetRandomLocation (var l: location);
  394.     begin
  395.         GetRandomLandLocation(l, All_Locations);
  396.     end;
  397.  
  398.     function CalcPercentageOfLand (l: lands): integer;
  399.         var
  400.             r, c: integer;
  401.             solid, land: longInt;
  402.     begin
  403.         solid := 0;
  404.         land := 0;
  405.         for r := 1 to rows do begin
  406.             for c := 1 to cols do begin
  407.                 if (lp^[r, c] <> L_River) & (lp^[r, c] <> L_Boat) then begin
  408.                     solid := solid + 1;
  409.                     if lp^[r, c] = l then
  410.                         land := land + 1;
  411.                 end;
  412.             end;
  413.         end;
  414.         CalcPercentageOfLand := land * 100 div solid;
  415.     end;
  416.  
  417.     function CountLand (ls: landSet): longInt;
  418.         var
  419.             r, c: integer;
  420.             count: longInt;
  421.     begin
  422.         count := 0;
  423.         for r := 1 to rows do begin
  424.             for c := 1 to cols do begin
  425.                 if lp^[r, c] in ls then begin
  426.                     count := count + 1;
  427.                 end;
  428.             end;
  429.         end;
  430.         CountLand := count;
  431.     end;
  432. {$D+}
  433.  
  434.     procedure AddDeepSea;
  435.         var
  436.             r, c: integer;
  437.             dr, dc: integer;
  438.             rr, cc: integer;
  439.             count: integer;
  440.             allsea: boolean;
  441.     begin
  442.         StartPart(rows);
  443.         for r := 1 to rows do begin
  444.             ProgRow(r);
  445.             for c := 1 to cols do begin
  446.                 allsea := true;
  447.                 for dr := -2 to 2 do begin
  448.                     for dc := -2 to 2 do begin
  449.                         if abs(dr) + abs(dc) <= 3 then begin
  450.                             rr := r + dr;
  451.                             cc := c + dc;
  452.                             if (1 <= rr) & (rr <= rows) & (1 <= cc) & (cc <= cols) & not (lp^[rr, cc] in [L_River, L_DeepSea]) then begin
  453.                                 allsea := false;
  454.                                 leave; { should leave both dr and dc loops, oh well }
  455.                             end;
  456.                         end;
  457.                     end; { dc}
  458.                 end; { dr }
  459.                 if allsea then
  460.                     lp^[r, c] := L_DeepSea;
  461.             end; { c}
  462.         end; { r }
  463.     end;
  464.  
  465.     procedure AddForrests;
  466.         var
  467.             l, m: location;
  468.             i, p, f: integer;
  469.             dr, dc: integer;
  470.             doit: boolean;
  471.             forest_needed, forest_sofar, divider: longInt;
  472.     begin
  473.         forest_sofar := 0;
  474.         forest_needed := CountLand([L_Grass]) * forest div 100;
  475.         divider := forest_needed div 100 + 1;
  476.         StartPart(forest_needed div divider);
  477.         while forest_sofar < forest_needed do begin
  478.             ProgRow(forest_sofar div divider);
  479.             InitQue;
  480.             GetRandomLandLocation(l, [L_Grass]);
  481.             AddQue(l);
  482.             p := RandBetween(20, 500);
  483.             for i := 1 to p do begin
  484.                 if EmptyQue then
  485.                     leave;
  486.                 GetQue(l);
  487.                 if lp^[l.r, l.c] = L_Grass then begin
  488.                     lp^[l.r, l.c] := L_Forest;
  489.                     forest_sofar := forest_sofar + 1;
  490.                     for dr := -1 to 1 do begin
  491.                         for dc := -1 to 1 do begin
  492.                             m.r := l.r + dr;
  493.                             m.c := l.c + dc;
  494.                             if ((dr <> 0) or (dc <> 0)) & (lp^[m.r, m.c] = L_Grass) & (Rand(10) < 5) then begin
  495.                                 AddQue(m);
  496.                             end; { if }
  497.                         end; { for dc }
  498.                     end; { for dr }
  499.                 end; { if still grass }
  500.             end; { for i }
  501.         end; { while }
  502.     end; { proc }
  503.  
  504.     procedure AddRivers;
  505.     begin
  506.     end;
  507.  
  508.     procedure AddRoads;
  509.     begin
  510.     end;
  511.  
  512.     procedure FillOutLandscape;
  513.     begin
  514.         ConvertToLand;
  515.         AddDeepSea;
  516.         AddForrests;
  517.         AddRivers;
  518.         AddRoads;
  519.     end;
  520.  
  521.     procedure PlaceBases;
  522.         var
  523.             i: integer;
  524.             l: location;
  525.     begin
  526.         for i := 1 to bases do begin
  527.             GetRandomLandLocation(l, [L_Swamp, L_Crater, L_Road, L_Forest, L_Rubble, L_Grass, L_Forest]);
  528.             if lp^[l.r, l.c] = L_Forest then
  529.                 lp^[l.r, l.c] := L_Grass;
  530.             base_locations[i] := l;
  531.         end;
  532.     end;
  533.  
  534.     procedure PlacePillboxes;
  535.         var
  536.             i: integer;
  537.             l: location;
  538.     begin
  539.         for i := 1 to pillboxes do begin
  540.             GetRandomLandLocation(l, [L_Swamp, L_Crater, L_Road, L_Forest, L_Rubble, L_Grass, L_Forest]);
  541.             if lp^[l.r, l.c] = L_Forest then
  542.                 lp^[l.r, l.c] := L_Grass;
  543.             pillbox_locations[i] := l;
  544.         end;
  545.     end;
  546.  
  547.     procedure BuildMap;
  548.     begin
  549.         InitLocations;
  550.         RandomHeights;
  551.         Smooth;
  552.         Threshold(FindHeight(land));
  553.         LoseIslands;
  554.         TrimEdges;
  555.         FillOutLandscape;
  556.         PlaceBases;
  557.         PlacePillboxes;
  558.     end;
  559.  
  560.     procedure WriteMap;
  561.         var
  562.             refnum: integer;
  563.             roff, coff: integer;
  564.  
  565.         procedure WriteData (p: ptr; count: longInt);
  566.             var
  567.                 oe: OSErr;
  568.         begin
  569.             if count > 0 then
  570.                 oe := FSWrite(refnum, count, p);
  571.         end;
  572.  
  573.         procedure WriteString (s: str255);
  574.             var
  575.                 count: longInt;
  576.                 oe: OSErr;
  577.         begin
  578.             count := length(s);
  579.             if length(s) > 0 then
  580.                 oe := FSWrite(refnum, count, @s[1]);
  581.         end;
  582.  
  583.         procedure WriteByte (b: integer);
  584.         begin
  585.             WriteString(chr(b));
  586.         end;
  587.  
  588.         procedure WriteLocation (var l: location);
  589.         begin
  590.             WriteByte(l.c + coff);
  591.             WriteByte(l.r + roff);
  592.         end;
  593.  
  594.         procedure WritePreamble;
  595.         begin
  596.             WriteString('BMAPBOLO');
  597.             WriteByte(version);
  598.             WriteByte(pillboxes);
  599.             WriteByte(bases);
  600.             WriteByte(max_starts);
  601.         end;
  602.  
  603.         procedure WritePillboxInfo;
  604.             var
  605.                 i: integer;
  606.         begin
  607.             for i := 1 to pillboxes do begin
  608.                 WriteLocation(pillbox_locations[i]);
  609.                 WriteByte($FF); { owner }
  610.                 WriteByte(15); { strength - full }
  611.                 WriteByte(50); { speed - initially sleepy }
  612.             end;
  613.         end;
  614.  
  615.         procedure WriteBaseInfo;
  616.             var
  617.                 i: integer;
  618.         begin
  619.             for i := 1 to bases do begin
  620.                 WriteLocation(base_locations[i]);
  621.                 WriteByte($FF); { owner }
  622.                 WriteByte(base_armour); { armour (0-90) }
  623.                 WriteByte(base_shells); { shells (0-90) }
  624.                 WriteByte(base_mines); { mines (0-90) }
  625.             end;
  626.         end;
  627.  
  628.         procedure WriteStartInfo;
  629.             procedure WriteStart (r, c, d: integer);
  630.                 var
  631.                     l: location;
  632.             begin
  633.                 l.r := r;
  634.                 l.c := c;
  635.                 WriteLocation(l);
  636.                 WriteByte(d);
  637.             end;
  638.             var
  639.                 i: integer;
  640.         begin
  641.             WriteStart(-2, -2, 14);
  642.             WriteStart(rows + 2, -2, 2);
  643.             WriteStart(rows + 2, cols + 2, 6);
  644.             WriteStart(-2, cols + 2, 10);
  645.             for i := 1 to 3 do begin
  646.                 WriteStart(-2, cols * i div 4, 12);
  647.                 WriteStart(rows + 2, cols * i div 4, 4);
  648.             end;
  649.             for i := 1 to 3 do begin
  650.                 WriteStart(rows * i div 4, -2, 0);
  651.                 WriteStart(rows * i div 4, cols + 2, 8);
  652.             end;
  653.         end;
  654.  
  655.         procedure WriteHeader;
  656.         begin
  657.             WritePreamble;
  658.             WritePillboxInfo;
  659.             WriteBaseInfo;
  660.             WriteStartInfo;
  661.         end;
  662.  
  663.         procedure WriteRows;
  664.  
  665.             var
  666.                 nibble_flag: boolean;
  667.                 nibble_data: integer;
  668.                 nibbles: packed array[0..512] of byte;
  669.  
  670.             procedure PutNibble (n: integer);
  671.             begin
  672.                 if not nibble_flag then begin
  673.                     nibble_flag := true;
  674.                     nibbles[nibble_data] := BSL(n, 4);
  675.                 end
  676.                 else begin
  677.                     nibble_flag := false;
  678.                     nibbles[nibble_data] := BOR(nibbles[nibble_data], n);
  679.                     nibble_data := nibble_data + 1;
  680.                 end;
  681.             end;
  682.  
  683.             var
  684.                 code, r, c: integer;
  685.                 t: lands;
  686.                 ds, i: integer;
  687.                 startc: integer;
  688.         begin
  689.             StartPart(rows);
  690.             r := 1;
  691.             c := 1;
  692.             while (r <= rows) do begin
  693.                 if c > cols then begin
  694.                     c := 1;
  695.                     r := r + 1;
  696.                     ProgRow(r);
  697.                 end;
  698.                 while (r <= rows) & (lp^[r, c] = L_DeepSea) do begin
  699.                     c := c + 1;
  700.                     if c > cols then begin
  701.                         c := 1;
  702.                         r := r + 1;
  703.                         ProgRow(r);
  704.                     end;
  705.                 end;
  706.  
  707.                 if r <= rows then begin
  708.                     startc := c;
  709.                     nibble_flag := false;
  710.                     nibble_data := 0;
  711.                     while (c <= cols) & (lp^[r, c] <> L_DeepSea) do begin
  712.                         t := lp^[r, c];
  713.                         if (c < cols) & (t = lp^[r, c + 1]) then begin
  714.                             code := 8; { 8 means 2 repeated squares }
  715.                             c := c + 2;
  716.                             while (code < 15) & (c <= cols) & (lp^[r, c] = t) do begin
  717.                                 code := code + 1;
  718.                                 c := c + 1;
  719.                             end;
  720.                             PutNibble(code);
  721.                             PutNibble(ord(t));
  722.                         end
  723.                         else begin
  724.                             code := 0; { 0 means 1 individual square }
  725.                             ds := c;
  726.                             c := c + 1;
  727.                             while (code < 7) & (c <= cols) & (lp^[r, c] <> L_DeepSea) & ((c = cols) | (lp^[r, c] <> lp^[r, c + 1])) do begin
  728.                                 code := code + 1;
  729.                                 c := c + 1;
  730.                             end;
  731.                             PutNibble(code);
  732.                             for i := ds to c - 1 do
  733.                                 PutNibble(ord(lp^[r, i]));
  734.                         end;
  735.                     end;
  736.                     if nibble_flag then
  737.                         PutNibble(0);
  738.                     WriteByte(nibble_data + 4);
  739.                     WriteByte(r + roff);
  740.                     WriteByte(startc + coff);
  741.                     WriteByte(c + coff);
  742.                     WriteData(@nibbles, nibble_data);
  743.                 end; { if r<=rows }
  744.             end; { while r<=rows }
  745.             WriteByte(4);
  746.             WriteByte($FF);
  747.             WriteByte($FF);
  748.             WriteByte($FF);
  749.         end; { proc }
  750.  
  751.         var
  752.             oe: OSErr;
  753.             fs: FSSpec;
  754.             where: point;
  755.             reply: MySFreply;
  756.     begin
  757.         roff := (256 - rows) div 2;
  758.         coff := (256 - cols) div 2;
  759.         SetPt(where, 40, 40);
  760.         PutFile('Save File as:', 'Random Map', reply);
  761.         with reply do begin
  762.             if Rgood then begin
  763.                 oe := HCreate(RvRefNum, RdirID, RfName, 'BOLO', 'BMAP');
  764.                 if oe = dupFnErr then begin
  765.                     oe := HDelete(RvRefNum, RdirID, RfName);
  766.                     oe := HCreate(RvRefNum, RdirID, RfName, 'BOLO', 'BMAP');
  767.                 end;
  768.                 oe := HOpen(RvRefNum, RdirID, RfName, fsWrPerm, refnum);
  769.                 if oe = noErr then begin
  770.                     WriteHeader;
  771.                     WriteRows;
  772.                     oe := FSClose(refnum);
  773.                 end;
  774.             end;
  775.         end;
  776.     end;
  777.  
  778.     function GetParameters: boolean;
  779.         var
  780.             dlg: dialogPtr;
  781.         procedure GetPair (item, dispitem: integer; var v: integer; min, max, rmin, rmax: integer);
  782.             var
  783.                 s1, s2: str255;
  784.         begin
  785.             GetItemText(dlg, item, s1);
  786.             GetItemText(dlg, item + 1, s2);
  787.             if (s1 <> '') | (s2 <> '') then begin
  788.                 if s1 = '' then
  789.                     s1 := s2;
  790.                 if s2 = '' then
  791.                     s2 := s1;
  792.                 rmin := StrToNum(s1);
  793.                 rmax := StrToNum(s2);
  794.             end;
  795.             if rmin > rmax then begin
  796.                 v := rmin;
  797.                 rmin := rmax;
  798.                 rmax := v;
  799.             end;
  800.             if rmin < min then
  801.                 rmin := min;
  802.             if rmax < min then
  803.                 rmax := min;
  804.             if rmin > max then
  805.                 rmin := max;
  806.             if rmax > max then
  807.                 rmax := max;
  808.             v := RandBetween(rmin, rmax);
  809.             SetItemText(display, dispitem, NumToStr(v));
  810.         end;
  811.  
  812.         var
  813.             good: boolean;
  814.             item: integer;
  815.     begin
  816.         dlg := GetNewDialog(200, nil, POINTER(-1));
  817.         SetUpDefaultOutline(dlg, 1, 3);
  818.         ShowWindow(dlg);
  819.         ModalDialog(nil, item);
  820.         good := item = 1;
  821.         if good then begin
  822.             display := GetNewDialog(201, nil, POINTER(-1));
  823.             SetDItemHandle(display, 1, handle(@DrawProgress));
  824.             GetPair(4, 2, rows, 10, 200, 50, 100);
  825.             GetPair(6, 3, cols, 10, 200, rows, rows); { make it square if no cols sepcified }
  826.             GetPair(8, 4, land, 15, 100, 25, 70);
  827.             GetPair(10, 5, forest, 0, 90, 50, 90);
  828.             GetPair(12, 6, bases, 0, 16, 8, 16);
  829.             GetPair(14, 7, pillboxes, 0, 16, 8, 16);
  830.             GetPair(16, 8, base_armour, 0, 90, 90, 90);
  831.             GetPair(18, 9, base_shells, 0, 90, 90, 90);
  832.             GetPair(20, 10, base_mines, 0, 90, 90, 90);
  833.             DisposeDialog(dlg);
  834.             ShowWindow(display);
  835.         end
  836.         else begin
  837.             DisposeDialog(dlg);
  838.         end;
  839.         GetParameters := good;
  840.     end;
  841.  
  842.     var
  843.         a: integer;
  844. begin
  845.     if Get1Resource('BNDL', 128) = nil then begin
  846.         SysBeep(1);
  847.         halt;
  848.     end;
  849.     SetDAFont(geneva);
  850.     InitUtilities;
  851.     GetDateTime(randseed);
  852.     mp := mapPtr(NewPtr(SizeOf(mapArray)));
  853.     lp := landPtr(mp);
  854.     mp2 := mapPtr(NewPtr(SizeOf(mapArray)));
  855.     lp2 := landPtr(mp2);
  856.  
  857.     if (mp <> nil) & (mp2 <> nil) then begin
  858.         InitCursor;
  859.         if GetParameters then begin
  860.             rows := rows + 2;  { leave room on the edge for the sea }
  861.             cols := cols + 2;  { leave room on the edge for the sea }
  862.             prog_parts := 8;
  863.             prog_parts_done := -1;
  864.             prog_base := rows;
  865.             prog_base_done := 0;
  866.             BuildMap;
  867.             if random_location_failed then begin
  868.                 a := Alert(160, nil);
  869.             end
  870.             else begin
  871.                 DrawMap;
  872.                 WriteMap;
  873.             end;
  874.             WNE;
  875.         end;
  876.     end;
  877. end.
  878. ShowText;
  879. DrawMap;